package ch.fhnw.apsi.services;

import static ch.fhnw.apsi.beans.BeanHelper.mapToBean;

import java.sql.SQLException;
import java.util.Map;
import java.util.Map.Entry;
import java.util.SortedMap;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import ch.fhnw.apsi.Page;
import ch.fhnw.apsi.beans.Credentials;
import ch.fhnw.apsi.beans.Firma;
import ch.fhnw.apsi.db.DBManager;
import ch.fhnw.apsi.db.Id;
import ch.fhnw.apsi.db.InvalidInputException;
import ch.fhnw.apsi.mail.Mailer;
import ch.fhnw.apsi.mail.MailingException;
import ch.fhnw.apsi.password.PasswordHash;
import ch.fhnw.apsi.password.PasswortGenerator;

public class Register implements Service {
  @Override
  public ServiceResult process(final HttpServletRequest request, final HttpServletResponse response) {
    final Firma firma = new Firma();
    if ("POST".equals(request.getMethod())) {
      final Map<String, String> map = ServiceHelper.getParameterMap(request);
      final SortedMap<String, Exception> mapToBean = mapToBean(map, firma, Id.class);
      final StringBuilder sb = new StringBuilder("Folgende Fehler sind aufgetreten:\n");
      boolean valid = true; // is the user input valid?
      if (!mapToBean.isEmpty()) {
        valid = false;
        // The Exceptions of Firma are save to show to the user:
        for (final Entry<String, Exception> e : mapToBean.entrySet())
          if (e.getValue() instanceof InvalidInputException)
            sb.append(e.getKey()).append(": ").append(e.getValue().getMessage()).append("\n");
          else
            sb.append(e.getKey()).append(": ").append("Ungültiger Input").append("\n");
      } else
        try {
          firma.validate();
        } catch (final Exception e) {
          valid = false;
          sb.append(e.getMessage());
        }
      if (!valid)
        return ServiceResult.error(400, sb.toString());
      final char[] pw = new char[PasswortGenerator.LENGTH];
      Credentials credentials;
      try {
        credentials = DBManager.getDB().createFirma(firma, pw);
      } catch (final SQLException e) {
        return ServiceResult.error(400, sb.toString());
      }
      // The char[] would be a bit more secure than a String, but
      final String password = new String(pw);
      assert assertPassword(password, credentials.getPasswortHash());
      // scramble the password in the array:
      PasswortGenerator.randomPasswort(pw);

      try {
        Mailer.sendRegistrationMail(firma, credentials.getUsername(), password);
      } catch (final MailingException e) {
        try {
          DBManager.getDB().deleteFirma(firma);
        } catch (final SQLException e1) {
          // too bad!
        }
        return ServiceResult.error(400, "Email konnte nicht verschickt werden");
      }

      // Now the user can be redirected to the success page:
      // response.sendRedirect(response.encodeRedirectURL(request.getContextPath() + "/app/success"));
      return ServiceResult
          .success("Sie haben sich erfolgreich registriert. Ihr Username und Passwort senden wir Ihnen per E-Mail.");
    } // GET: return the empty Firma.
    return new ServiceResult(firma, Page.REGISTER);
  }

  static boolean assertPassword(final String pw, final String hash) {
    try {
      return PasswordHash.validatePassword(pw, hash);
    } catch (final Throwable t) {
      return false;
    }
  }
}
